ffa032
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponseWrapper;
 
@@ -53,74 +54,75 @@
public class ResourceUrlEncodingFilter extends GenericFilterBean {
 	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
 			throws IOException, ServletException {
 		if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
-			throw new ServletException("ResourceUrlEncodingFilter just supports HTTP requests");
+			throw new ServletException("ResourceUrlEncodingFilter only supports HTTP requests");
 		}
-		HttpServletRequest httpRequest = (HttpServletRequest) request;
-		HttpServletResponse httpResponse = (HttpServletResponse) response;
-		filterChain.doFilter(httpRequest, new ResourceUrlEncodingResponseWrapper(httpRequest, httpResponse));
+		ResourceUrlEncodingRequestWrapper wrappedRequest =
+				new ResourceUrlEncodingRequestWrapper((HttpServletRequest) request);
+		ResourceUrlEncodingResponseWrapper wrappedResponse =
+				new ResourceUrlEncodingResponseWrapper(wrappedRequest, (HttpServletResponse) response);
+		filterChain.doFilter(wrappedRequest, wrappedResponse);
 	}
 
+	private static class ResourceUrlEncodingRequestWrapper extends HttpServletRequestWrapper {
 
-	private static class ResourceUrlEncodingResponseWrapper extends HttpServletResponseWrapper {
-
-		private final HttpServletRequest request;
+		@Nullable
+		private ResourceUrlProvider resourceUrlProvider;
 
-		/* Cache the index and prefix of the path within the DispatcherServlet mapping */
 		@Nullable
 		private Integer indexLookupPath;
 
 		private String prefixLookupPath = "";
 
-		public ResourceUrlEncodingResponseWrapper(HttpServletRequest request, HttpServletResponse wrapped) {
-			super(wrapped);
-			this.request = request;
+		ResourceUrlEncodingRequestWrapper(HttpServletRequest request) {
+			super(request);
 		}
 
 		@Override
-		public String encodeURL(String url) {
-			ResourceUrlProvider resourceUrlProvider = getResourceUrlProvider();
-			if (resourceUrlProvider == null) {
-				logger.trace("ResourceUrlProvider not available via " +
-						"request attribute ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR");
-				return super.encodeURL(url);
-			}
-
-			int index = initLookupPath(resourceUrlProvider);
-			if (url.startsWith(this.prefixLookupPath)) {
-				int suffixIndex = getQueryParamsIndex(url);
-				String suffix = url.substring(suffixIndex);
-				String lookupPath = url.substring(index, suffixIndex);
-				lookupPath = resourceUrlProvider.getForLookupPath(lookupPath);
-				if (lookupPath != null) {
-					return super.encodeURL(this.prefixLookupPath + lookupPath + suffix);
+		public void setAttribute(String name, Object o) {
+			super.setAttribute(name, o);
+			if (ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR.equals(name)) {
+				if(o instanceof ResourceUrlProvider) {
+					initLookupPath((ResourceUrlProvider) o);
 				}
 			}
 
-			return super.encodeURL(url);
-		}
-
-		@Nullable
-		private ResourceUrlProvider getResourceUrlProvider() {
-			return (ResourceUrlProvider) this.request.getAttribute(
-					ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR);
 		}
 
-		private int initLookupPath(ResourceUrlProvider urlProvider) {
+		private void initLookupPath(ResourceUrlProvider urlProvider) {
+			this.resourceUrlProvider = urlProvider;
 			if (this.indexLookupPath == null) {
-				UrlPathHelper pathHelper = urlProvider.getUrlPathHelper();
-				String requestUri = pathHelper.getRequestUri(this.request);
-				String lookupPath = pathHelper.getLookupPathForRequest(this.request);
+				UrlPathHelper pathHelper = this.resourceUrlProvider.getUrlPathHelper();
+				String requestUri = pathHelper.getRequestUri(this);
+				String lookupPath = pathHelper.getLookupPathForRequest(this);
 				this.indexLookupPath = requestUri.lastIndexOf(lookupPath);
 				this.prefixLookupPath = requestUri.substring(0, this.indexLookupPath);
 				if ("/".equals(lookupPath) && !"/".equals(requestUri)) {
-					String contextPath = pathHelper.getContextPath(this.request);
+					String contextPath = pathHelper.getContextPath(this);
 					if (requestUri.equals(contextPath)) {
 						this.indexLookupPath = requestUri.length();
 						this.prefixLookupPath = requestUri;
 					}
 				}
 			}
-			return this.indexLookupPath;
+		}
+
+		@Nullable
+		public String resolveUrlPath(String url) {
+			if (this.resourceUrlProvider == null) {
+				logger.trace("ResourceUrlProvider not available via " +
+						"request attribute ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR");
+				return null;
+			}
+			if (url.startsWith(this.prefixLookupPath)) {
+				int suffixIndex = getQueryParamsIndex(url);
+				String suffix = url.substring(suffixIndex);
+				String lookupPath = url.substring(this.indexLookupPath, suffixIndex);
+				lookupPath = this.resourceUrlProvider.getForLookupPath(lookupPath);
+				if (lookupPath != null) {
+					return this.prefixLookupPath + lookupPath + suffix;
+				}
+			}
+			return null;
 		}
 
 		private int getQueryParamsIndex(String url) {
@@ -129,4 +131,24 @@
public class ResourceUrlEncodingFilter extends GenericFilterBean {
 		}
 	}
 
+
+	private static class ResourceUrlEncodingResponseWrapper extends HttpServletResponseWrapper {
+
+		private final ResourceUrlEncodingRequestWrapper request;
+
+		ResourceUrlEncodingResponseWrapper(ResourceUrlEncodingRequestWrapper request, HttpServletResponse wrapped) {
+			super(wrapped);
+			this.request = request;
+		}
+
+		@Override
+		public String encodeURL(String url) {
+			String urlPath = this.request.resolveUrlPath(url);
+			if (urlPath != null) {
+				return super.encodeURL(urlPath);
+			}
+			return super.encodeURL(url);
+		}
+	}
+
 }
